<template>
  <div class="container">
    <h1>二维码识别</h1>
    <div class="upload-area">
      <el-upload
        class="upload-component"
        drag
        action="#"
        :auto-upload="false"
        :show-file-list="false"
        accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt"
        @change="handleFileChange"
        @drop.prevent="handleDrop"
        @dragover.prevent="handleDragOver"
        @dragleave.prevent="handleDragLeave">
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">
          拖拽图片到此处或 <em>点击上传</em>
        </div>
      </el-upload>
    </div>

    <div v-if="qrResult" class="result-panel">
      <h3>识别结果</h3>
      <div class="result-content">
        <p>{{ qrResult }}</p>
        <el-button type="primary" @click="copyResult">复制内容</el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { UploadFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { BrowserQRCodeReader, BrowserMultiFormatReader } from '@zxing/browser'
import { DecodeHintType } from '@zxing/library'

const qrResult = ref('')

// 图像预处理函数
const preprocessImage = (context, width, height) => {
  // 增强对比度
  const imageData = context.getImageData(0, 0, width, height)
  const data = imageData.data
  for (let i = 0; i < data.length; i += 4) {
    const avg = (data[i] + data[i + 1] + data[i + 2]) / 3
    const threshold = 128
    const value = avg < threshold ? 0 : 255
    data[i] = data[i + 1] = data[i + 2] = value
  }
  context.putImageData(imageData, 0, 0)
}

const handleFileChange = async (file) => {
  try {
    const reader = new FileReader()
    reader.onload = async (e) => {
      const codeReader = new BrowserQRCodeReader()
      try {
        // 创建一个临时的img元素来获取图片URL
        const img = new Image()
        img.src = e.target.result
        await new Promise((resolve) => {
          img.onload = resolve
        })

        // 创建canvas来处理图片
        const canvas = document.createElement('canvas')
        const context = canvas.getContext('2d')
        
        // 设置合适的图像大小
        const maxSize = 1200
        let width = img.width
        let height = img.height
        
        if (Math.max(width, height) > maxSize) {
          const ratio = maxSize / Math.max(width, height)
          width *= ratio
          height *= ratio
        }
        
        canvas.width = width
        canvas.height = height
        context.drawImage(img, 0, 0, width, height)
        
        // 将canvas转换为Blob URL
        const blob = await new Promise(resolve => canvas.toBlob(resolve))
        const imageUrl = URL.createObjectURL(blob)

        // 预处理图像
        preprocessImage(context, width, height)
        
        // 配置ZXing参数
        const hints = new Map()
        hints.set(DecodeHintType.TRY_HARDER, true)
        hints.set(DecodeHintType.POSSIBLE_FORMATS, ['QR_CODE', 'DATA_MATRIX', 'AZTEC'])
        
        // 创建多格式读取器
        const multiReader = new BrowserMultiFormatReader(hints)
        
        // 多次尝试识别
        let result = null
        try {
          // 尝试使用多格式读取器
          result = await multiReader.decodeFromImageUrl(imageUrl)
        } catch (e) {
          // 如果失败，尝试使用标准二维码读取器
          try {
            result = await codeReader.decodeFromImageUrl(imageUrl)
          } catch (e2) {
            // 两种方法都失败，抛出错误
            throw new Error('No QR code found')
          }
        }
        
        if (result) {
          qrResult.value = result.getText()
        } else {
          throw new Error('No QR code found')
        }

        // 清理资源
        URL.revokeObjectURL(imageUrl)
      } catch (error) {
        ElMessage.error({
          message: '未能识别二维码，请确保图片清晰且包含完整的二维码',
          duration: 5000
        })
      }
    }
    reader.readAsDataURL(file.raw)
  } catch (error) {
    ElMessage.error({
      message: '图片处理过程中出现错误',
      duration: 5000
    })
  }
}

const handleDrop = () => {
  const uploadDragger = document.querySelector('.el-upload-dragger')
  if (uploadDragger) {
    uploadDragger.classList.remove('is-dragover')
    uploadDragger.style.cursor = ''
  }
}

const handleDragOver = () => {
  const uploadDragger = document.querySelector('.el-upload-dragger')
  if (uploadDragger) {
    uploadDragger.classList.add('is-dragover')
    uploadDragger.style.cursor = 'copy'
  }
}

const handleDragLeave = () => {
  const uploadDragger = document.querySelector('.el-upload-dragger')
  if (uploadDragger) {
    uploadDragger.classList.remove('is-dragover')
    uploadDragger.style.cursor = ''
  }
}

const copyResult = async () => {
  try {
    await navigator.clipboard.writeText(qrResult.value)
    ElMessage.success('复制成功')
  } catch (err) {
    ElMessage.error('复制失败')
  }
}
</script>

<style scoped>
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

h1 {
  text-align: center;
  margin-bottom: 30px;
}

.upload-area {
  margin-bottom: 30px;
}

.upload-component {
  width: 100%;
}

.upload-component :deep(.el-upload) {
  width: 100%;
}

.upload-component :deep(.el-upload-dragger) {
  width: 100%;
  height: 200px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: 2px dashed var(--el-border-color);
  border-radius: 8px;
  transition: all 0.3s;
}

.upload-component :deep(.el-upload-dragger:hover),
.upload-component :deep(.el-upload-dragger.is-dragover) {
  background-color: var(--el-color-primary-light-9);
  border-color: var(--el-color-primary);
}

.upload-component :deep(.el-icon--upload) {
  font-size: 48px;
  color: var(--el-color-primary);
  margin-bottom: 16px;
}

.upload-component :deep(.el-upload__text) {
  color: var(--el-text-color-regular);
  font-size: 16px;
}

.upload-component :deep(.el-upload__text em) {
  color: var(--el-color-primary);
  font-style: normal;
  font-weight: bold;
}

.result-panel {
  background-color: #f5f7fa;
  padding: 20px;
  border-radius: 8px;
  margin-top: 20px;
}

.result-panel h3 {
  margin: 0 0 15px 0;
  color: var(--el-text-color-primary);
}

.result-content {
  background-color: white;
  padding: 15px;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.result-content p {
  margin: 0 0 15px 0;
  word-break: break-all;
}
</style>